import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.Vector;


public class Serveur extends UnicastRemoteObject implements IServeur {

	private static final long serialVersionUID = 1L;
	private Serveur serveur;
	private IIHM rmiIHM;
	
	private static ServeurCommunication com;
	// Vrai si un enregistrement de trajet est en cours
	private boolean saving=false;
	// Sauvegarde du num�ro trajet en cours de param�trage
	private int currentSaving;
	
	// Sauvegarde des lieu d�fini
	private Vector<Lieu> vectorLieu;
	// Sauvegarde de la touche actuellement appuyée
	private int actualKeyPressed=0;	
	
	
	public static void main(String[] args) {
		
		if(System.getSecurityManager()==null){//On attribue tous les droits via le SecurityManager
            System.setProperty("java.security.policy", System.getProperty("user.dir")+"\\java.policy");
		}
	    try {
	    	String name="//localhost:4567/Interface_Serveur";
			Serveur mainServeur = new Serveur();
			Registry registry=LocateRegistry.createRegistry(4567);//Registry = base regroupant les interfaces
	    	Naming.rebind (name, mainServeur);
			System.out.println ("Serveur prêt, Rebind OK.") ;
		} catch (Exception e) {
			System.out.println ("ERREUR Initialisation") ;
			e.printStackTrace();
			System.exit(0);
		}
	}

	@Override
	public void connectRMI() throws RemoteException {
		try {
			rmiIHM = (IIHM) Naming.lookup("rmi://127.0.0.1:4568/Interface_IHM");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	//Constructeur
	public Serveur() throws RemoteException {
		super();	
	    try {
			com = new ServeurCommunication(this);
			vectorLieu = new Vector<Lieu>();
		} catch (Exception e) {
			System.out.println ("ERREUR Initialisation") ;
			e.printStackTrace();
			System.exit(0);
		}
	}
	
	/////////////////////Définition des méthodes
	
	public void incident() {
		com.kill();
		printInfo("Incident technique");
		setNTXConnexion(false);
	}
	
	public void setNTXConnexion(boolean b) {
		if(b){
			com.start();
		}
		try {
			rmiIHM.etatConnect(b);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}


	//Définit les actions à effectuer lors de l'appui sur une touche
	@Override
	public void keyPressed(int key) throws RemoteException {
	// Si on est en cours de programmation d'un itinéraire
		// Sinon on ne fait rien
		if(saving){
			// Si aucune touche n'est appuyée et on appuie sur la touche "haut"
			if(actualKeyPressed==0 && key==KeyEvent.VK_UP){
				actualKeyPressed=key;
				com.send('a');
				printInfo("Programmation du trajet " +vectorLieu.get(currentSaving).getNom()+ " : Avancer");
			}
			// Si aucune touche n'est appuyée et on appuie sur la touche "bas"
			else if(actualKeyPressed==0 && key==KeyEvent.VK_DOWN){
				actualKeyPressed=key;
				com.send('r');
				printInfo("Programmation du trajet " +vectorLieu.get(currentSaving).getNom()+ " : Reculer");	
			}
			// Si aucune touche n'est appuyée et on appuie sur la touche "gauche"
			else if(actualKeyPressed==0 && key==KeyEvent.VK_LEFT){
				actualKeyPressed=key;
				com.send('g');
				printInfo("Programmation du trajet " +vectorLieu.get(currentSaving).getNom()+ " : Tourner à gauche");		
			}
			// Si aucune touche n'est appuyée et on appuie sur la touche "droite"
			else if(actualKeyPressed==0 && key==KeyEvent.VK_RIGHT){
				actualKeyPressed=key;
				com.send('d');
				printInfo("Programmation du trajet " +vectorLieu.get(currentSaving).getNom()+ " : Tourner à droite");
			}
		}
	}

	//D�finit les actions � effectuer lors du relachement d'une touche
	@Override
	public void keyReleased(int key) throws RemoteException {
		// Si on est en cours de programmation d'un itin�raire
		// et que la touche relaché est la même que celle de l'action en cours
		if(saving && key==actualKeyPressed){
			com.send('s');
			actualKeyPressed=0;
			// Si la touche relachée est "haut"
			if(key==KeyEvent.VK_UP){
				printInfo("Programmation du trajet " +vectorLieu.get(currentSaving).getNom()+ " : Fin de l'action avancer");
			}
			// Si la touche relachée est "bas"
			else if(key==KeyEvent.VK_DOWN){
				printInfo("Programmation du trajet " +vectorLieu.get(currentSaving).getNom()+ " : Fin de l'action reculer");	
			}
		}
	}

	//Renvoie le vector contenant les Lieux
	@Override
	public Vector<Lieu> getVectorLieux() throws RemoteException {
		return vectorLieu;
	}

	//Ajoute un Lieu au vector
	@Override
	public void addLieu(String nom) throws RemoteException {
		vectorLieu.add(new Lieu(nom));
	}

	@Override
	public int getNbLieu() throws RemoteException {
		return vectorLieu.size();
	}


	@Override
	public void connecter(String nomBrique) throws RemoteException {
		printInfo("Connexion à la brique "+ nomBrique);
		com.connexion(nomBrique);
		printInfo("Connecté à la brique "+ nomBrique);
		
	}


	@Override
	public void deconnecter(String nomBrique) throws RemoteException {
		com.kill();
		printInfo("Déconnexion de la brique "+ nomBrique);
		setNTXConnexion(false);
	}


	@Override
	public void startEnreg(int id) throws RemoteException {
		currentSaving=id;
		printInfo("Début enregistrement trajet: " +vectorLieu.get(id).getNom());
		com.send('p');		
	}


	@Override
	public void stopEnreg(int id) throws RemoteException {
		saving=false;
		vectorLieu.get(id).setDefini(true);
		printInfo("Fin enregistrement trajet: " +vectorLieu.get(id).getNom());
		com.send('f');
	}


	@Override
	public void goTo(int id) throws RemoteException {
		printInfo("Direction " +vectorLieu.get(id).getNom());
		com.send(tranformeIntToCapitalLetter(id));
	}
	
	private char tranformeIntToCapitalLetter(int i){
		switch (i){
		case 0:
			return 'A';
		case 1:
			return 'B';
		case 2:
			return 'C';
		case 3:
			return 'D';
		case 4:
			return 'E';
		case 5:
			return 'F';
		case 6:
			return 'G';
		case 7:
			return 'H';
		case 8:
			return 'I';
		case 9:
			return 'J';
		default :
			return 'v';
		}
	}
	
	public void printInfo(String texte) {
			System.out.println(texte);
			try {
				rmiIHM.printInfo(texte);
			} catch (RemoteException e) {
				e.printStackTrace();
			}
	}

	public void interprete(char c) {
		try {
			if (c >= 'A' && c <= 'J') {
				int destination = fromCapitalLetterToInt(c);
				rmiIHM.printInfo("Robot arrivé dans la pièce : "+vectorLieu.get(destination).getNom());
				rmiIHM.setRobotInRoom();
			}
			else if(c=='X'){
				rmiIHM.printInfo("Robot déjà présent dans la pièce");
				rmiIHM.setRobotInRoom();
			}
			else if(c=='Y'){
				rmiIHM.printInfo("Robot revenu au point d'origine");
				rmiIHM.setRobotResetedAfterSave();
			}
			else if(c=='Z'){
				saving=true;
				rmiIHM.printInfo("Robot revenu au point d'origine, début de l'enregistrement");
				rmiIHM.setRobotResetedBeforeSave();
			}
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}
	
	private int fromCapitalLetterToInt(char c) {
		switch (c){
		case 'A':
			return 0;
		case 'B':
			return 1;
		case 'C':
			return 2;
		case 'D':
			return 3;
		case 'E':
			return 4;
		case 'F':
			return 5;
		case 'G':
			return 6;
		case 'H':
			return 7;
		case 'I':
			return 8;
		case 'J':
			return 9;
		default :
			return 20;
		}
	}
}
